/*
 * This file is part of aion-engine <aion-engine.com>
 *
 * aion-engine is private software: you can redistribute it and or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Private Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * aion-engine is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser Public License for more details.
 *
 * You should have received a copy of the GNU Lesser Public License
 * along with aion-engine.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.aionengine.gameserver.ai2.handler;

import com.aionengine.gameserver.ai2.NpcAI2;
import com.aionengine.gameserver.ai2.event.AIEventType;
import com.aionengine.gameserver.controllers.attack.AttackResult;
import com.aionengine.gameserver.controllers.attack.AttackStatus;
import com.aionengine.gameserver.model.TribeClass;
import com.aionengine.gameserver.model.gameobjects.Creature;
import com.aionengine.gameserver.model.gameobjects.Npc;
import com.aionengine.gameserver.model.gameobjects.VisibleObject;
import com.aionengine.gameserver.model.gameobjects.player.Player;
import com.aionengine.gameserver.model.templates.npc.NpcTemplateType;
import com.aionengine.gameserver.network.aion.serverpackets.SM_ATTACK;
import com.aionengine.gameserver.services.TribeRelationService;
import com.aionengine.gameserver.utils.MathUtil;
import com.aionengine.gameserver.utils.PacketSendUtility;
import com.aionengine.gameserver.utils.ThreadPoolManager;
import com.aionengine.gameserver.world.geo.GeoService;
import com.aionengine.gameserver.world.knownlist.Visitor;

import java.util.Collections;

/**
 * @author ATracer
 */
public class AggroEventHandler {

    /**
     * @param npcAI
     * @param myTarget
     */
    public static void onAggro(NpcAI2 npcAI, final Creature myTarget) {
        final Npc owner = npcAI.getOwner();
        // TODO move out?
        if (myTarget.getAdminNeutral() == 1 || myTarget.getAdminNeutral() == 3 || myTarget.getAdminEnmity() == 1
                || myTarget.getAdminEnmity() == 3 || TribeRelationService.isFriend(owner, myTarget))
            return;
        PacketSendUtility
                .broadcastPacket(
                        owner,
                        new SM_ATTACK(owner, myTarget, 0, 633, 0, Collections
                                .singletonList(new AttackResult(0, AttackStatus.NORMALHIT))));

        ThreadPoolManager.getInstance().schedule(new AggroNotifier(owner, myTarget, true), 500);
    }

    public static boolean onCreatureNeedsSupport(NpcAI2 npcAI, Creature notMyTarget) {
        Npc owner = npcAI.getOwner();
        if (TribeRelationService.isSupport(notMyTarget, owner) && MathUtil.isInRange(owner, notMyTarget, owner.getAggroRange())
                && GeoService.getInstance().canSee(owner, notMyTarget)) {
            VisibleObject myTarget = notMyTarget.getTarget();
            if (myTarget != null && myTarget instanceof Creature) {
                Creature targetCreature = (Creature) myTarget;
                PacketSendUtility.broadcastPacket(
                        owner,
                        new SM_ATTACK(owner, targetCreature, 0, 633, 0, Collections.singletonList(new AttackResult(0,
                                AttackStatus.NORMALHIT))));
                ThreadPoolManager.getInstance().schedule(new AggroNotifier(owner, targetCreature, false), 500);
                return true;
            }
        }
        return false;
    }

    public static boolean onGuardAgainstAttacker(NpcAI2 npcAI, Creature attacker) {
        Npc owner = npcAI.getOwner();
        TribeClass tribe = owner.getTribe();
        if (!tribe.isGuard() && owner.getObjectTemplate().getNpcTemplateType() != NpcTemplateType.GUARD) {
            return false;
        }
        VisibleObject target = attacker.getTarget();
        if (target != null && target instanceof Player) {
            Player playerTarget = (Player) target;
            if (!owner.isEnemy(playerTarget) && owner.isEnemy(attacker)
                    && MathUtil.isInRange(owner, playerTarget, owner.getAggroRange())
                    && GeoService.getInstance().canSee(owner, attacker)) {
                owner.getAggroList().startHate(attacker);
                return true;
            }
        }
        return false;
    }

    private static final class AggroNotifier implements Runnable {

        private Npc aggressive;
        private Creature target;
        private boolean broadcast;

        AggroNotifier(Npc aggressive, Creature target, boolean broadcast) {
            this.aggressive = aggressive;
            this.target = target;
            this.broadcast = broadcast;
        }

        @Override
        public void run() {
            aggressive.getAggroList().addHate(target, 1);
            if (broadcast) {
                aggressive.getKnownList().doOnAllNpcs(new Visitor<Npc>() {

                    @Override
                    public void visit(Npc object) {
                        object.getAi2().onCreatureEvent(AIEventType.CREATURE_NEEDS_SUPPORT, aggressive);
                    }
                });
            }
            aggressive = null;
            target = null;
        }

    }

}
